﻿#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
#define DISABLESTEAMWORKS
#endif

using LitJson;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

public class Player
{
    public Dictionary<Item.ItemsType, Item> Items { get { return m_Items; } set { m_Items = value; } }
    public static Player Instance = new Player();
    public List<Ship> m_Ships = new List<Ship>();
    public int m_LotteryLastTermNumber = 0;
    public int m_LotteryCurTermNumber = 0;
    public List<int> m_LotteryLastTerm = new List<int>();
    public List<int> m_LotteryCurTerm = new List<int>();
    public bool m_DevelopmentMode = false;
    public Driver.DriveLevel m_DriveLevel= Driver.DriveLevel.LEVEL_NULL;
    public const int EXAMINATION_NUMBER = 3;
    public int [,] DriveLicenseState = new int[(int)Driver.DriveLevel.LEVEL_D + 1, EXAMINATION_NUMBER];

    public int m_BattleLevel=1;
    public bool m_EasyOperation = false;
    public bool OpenAudio {
        get { return m_OpenAudio; } 
        set { 
            m_OpenAudio = value;
            AudioListener.pause = !m_OpenAudio;
        } 
    }
    public float m_UIScale=-1;

    bool m_OpenAudio = true;
    //  Shop
    public int m_ShopUpdateDate=0;
    public List<int> m_WeaponShopBuyIndices = new List<int> ();
    public List<int> m_ShipShopBuyIndices = new List<int>();


    public PlayerNetwork m_PlayerNetwork;
    public int SelectShip { set {
            if (m_Ships.Count <= value || value < 0)
            {
                m_SelectShip = -1;
                return;
            }
            m_SelectShip = value;
            onSwitchCurrentShip.Invoke(m_Ships[m_SelectShip]);
        } 
        get { return m_SelectShip; } }

    public int Money {
        set
        {
            m_Money = value;
#if !DISABLESTEAMWORKS
            if(UtilsGame.IsSteamMG())
            {
                int dbMoney = 0;
                if (Steamworks.SteamUserStats.GetStat("money_count", out dbMoney))
                {
                    if (dbMoney < m_Money)
                        Steamworks.SteamUserStats.SetStat("money_count", m_Money);
                }
                if (m_Money >= 10000)
                {
                    Steamworks.SteamUserStats.SetAchievement("TEN_THOUSAND_PEOPLE");
                    Steamworks.SteamUserStats.StoreStats();
                }
                if (m_Money >= 100000)
                {
                    Steamworks.SteamUserStats.SetAchievement("TEN_TEN_THOUSAND_PEOPLE");
                    Steamworks.SteamUserStats.StoreStats();
                }
                if (m_Money >= 1000000)
                {
                    Steamworks.SteamUserStats.SetAchievement("TEN_TEN_TEN_THOUSAND_PEOPLE");
                    Steamworks.SteamUserStats.StoreStats();
                }
            }
#endif
        }
        get { return m_Money; }
    }

    int m_Money = 80;
    int m_SelectShip=-1;
    public string ConfigPath = "./Player";

    Dictionary<Item.ItemsType, Item> m_Items = new Dictionary<Item.ItemsType, Item>();

    public CurrentShipSwitched onSwitchCurrentShip = new CurrentShipSwitched();
    public class CurrentShipSwitched: UnityEvent<Ship> { }

    private Player()
    {
#if UNITY_ANDROID
        ConfigPath = Application.persistentDataPath + "/Player";
#endif
    }
    public Ship GetCurrentShip()
    {
        if (m_SelectShip < 0 ||
            m_SelectShip >= m_Ships.Count)
            return null;

        return m_Ships[m_SelectShip];
    }

    public Ship placeSelectShip(Vector3 position, Quaternion rotation)
    {
        if (m_Ships.Count <= 0)
            return null;
        for(int i=0; i< m_Ships.Count; ++i)
        {
            m_Ships[i].gameObject.SetActive(false);
        }

        Ship retShip = null;
        if (m_Ships.Count > SelectShip && SelectShip >=0)
        {
            retShip = m_Ships[SelectShip];
        }
        else if (m_Ships.Count > 0)
        {
            m_SelectShip = 0;
            retShip = m_Ships[0];
        }
        else
            return null;

        retShip.gameObject.SetActive(true);
        retShip.gameObject.transform.position = position;
        retShip.gameObject.transform.rotation = rotation;
        return retShip;
    }

    public void addItem(Item.ItemsType type, int number = 1)
    {
        if(m_Items.ContainsKey(type))
        {
            m_Items[type].m_Number += number;
        }
        else
        {
            Item item = ItemFactory.Instance.createItem(Item.getItemEnumString(type));
            if(item != null)
            {
                item.m_Number = number;
                m_Items.Add(type, item);
            }
        }
    }

    public void addShip(Ship ship)
    {
        m_Ships.Add(ship);
    }
    public void RemoveShip(Ship ship)
    {
        Ship curShip = null;
        if (m_SelectShip >= 0)
            curShip = m_Ships[m_SelectShip];

        m_Ships.Remove(ship);
        if(curShip)
        {
            for (int i = 0; i < m_Ships.Count; ++i)
            {
                if (m_Ships[i] == curShip)
                {
                    SelectShip = i;
                }
            }
        }
        else
            SelectShip = -1;
    }
    public int GetNumShips()
    {
        return m_Ships.Count;
    }
    public Ship GetShip(int i)
    {
        return m_Ships[i];
    }
    public void removeItem(Item.ItemsType type, int number = 1)
    {
        if (m_Items.ContainsKey(type))
        {
            if(m_Items[type].m_Number <= number)
            {
                m_Items.Remove(type);
            }
            else
            {
                m_Items[type].m_Number -= number;
            }
        }
    }
    public void ShopBuyItem(int communityID)
    {
        for(int i=0; i< m_WeaponShopBuyIndices.Count; ++i)
        {
            if (m_WeaponShopBuyIndices[i] == (communityID % 1000))
            {
                m_WeaponShopBuyIndices[i] = communityID;
                return;
            }
        }
        m_WeaponShopBuyIndices.Add(communityID);
    }
    public void save()
    {
        JsonData root = new JsonData();
        
        /// Global
        root["DelvelopmentMode"] = m_DevelopmentMode;
        root["DriveLevel"] = (int)m_DriveLevel;
        root["BattleLevel"] = (int)m_BattleLevel;
        root["EasyOperation"] = m_EasyOperation;
        root["UIScale"] = m_UIScale;
        root["OpenAudio"] = OpenAudio;

        root["DriveLicenseState"] = new JsonData();
        root["DriveLicenseState"].SetJsonType(JsonType.Object);
        for(int i=0; i< (int)Driver.DriveLevel.LEVEL_D + 1; ++i)
        {
            var driveLevelState = new JsonData();
            driveLevelState.SetJsonType(JsonType.Array);
            for (int j=0; j< EXAMINATION_NUMBER; ++j)
            {
                driveLevelState.Add(DriveLicenseState[i, j]);
            }
            root["DriveLicenseState"]["DriveLevel" + i] = driveLevelState;
        }

        // Lottery
        root["Lottery"] = new JsonData();
        root["Lottery"].SetJsonType(JsonType.Object);
        root["Lottery"]["LastTermNumber"] = m_LotteryLastTermNumber;
        root["Lottery"]["LastTerm"] = new JsonData();
        root["Lottery"]["LastTerm"].SetJsonType(JsonType.Array);
        for (int i = 0; i < m_LotteryLastTerm.Count; ++i)
        {
            root["Lottery"]["LastTerm"].Add(m_LotteryLastTerm[i]);
        }

        root["Lottery"]["CurTermNumber"] = m_LotteryCurTermNumber;
        root["Lottery"]["CurTerm"] = new JsonData();
        root["Lottery"]["CurTerm"].SetJsonType(JsonType.Array);
        for (int i = 0; i < m_LotteryCurTerm.Count; ++i)
        {
            root["Lottery"]["CurTerm"].Add(m_LotteryCurTerm[i]);
        }

        /// Ships
        root["SelectShip"] = SelectShip;
        root["Money"] = m_Money;
        root["Ships"] = new JsonData();
        root["Ships"].SetJsonType(JsonType.Array);
        for (int i=0; i< m_Ships.Count; ++i)
        {
            var jsonShip = m_Ships[i].save();
            root["Ships"].Add(jsonShip);
        }

        /// Items 
        root["Items"] = new JsonData();
        root["Items"].SetJsonType(JsonType.Object);

        foreach (var item in m_Items)
        {
            string typeStr = Item.getItemEnumString(item.Key);
            root["Items"][typeStr] = item.Value.m_Number;
        }

        /// Shop
        root["Shop"] = new JsonData();
        root["Shop"].SetJsonType(JsonType.Object);
        root["Shop"]["UpdateDate"] = m_ShopUpdateDate;

        root["Shop"]["Weapon"] = new JsonData();
        root["Shop"]["Weapon"].SetJsonType(JsonType.Array);
        for (int i=0; i< m_WeaponShopBuyIndices.Count; ++i)
        {
            root["Shop"]["Weapon"].Add(m_WeaponShopBuyIndices[i]);
        }
        root["Shop"]["Ship"] = new JsonData();
        root["Shop"]["Ship"].SetJsonType(JsonType.Array);
        for (int i = 0; i < m_ShipShopBuyIndices.Count; ++i)
        {
            root["Shop"]["Ship"].Add(m_ShipShopBuyIndices[i]);
        }


        string data = root.ToJson();
        using (FileStream fs = new FileStream(ConfigPath, FileMode.Create, FileAccess.Write))
        {
            byte[] array = System.Text.Encoding.UTF8.GetBytes(data);
            fs.Write(array, 0, (int)array.Length);
            fs.Close();
        }
    }

    public void load()
    {
        string data;
        if (!File.Exists(ConfigPath))
        {
            var shipObj = GameObject.Instantiate( Resources.Load<GameObject>("Perfabs/Ships/Common/First"));
            m_Ships.Add(shipObj.GetComponent<Ship>()) ;
            return;
        }

        using (FileStream fs = new FileStream(ConfigPath, FileMode.Open, FileAccess.Read))
        {
            FileInfo info = new System.IO.FileInfo(ConfigPath);
            byte[] array = new byte[info.Length];
            fs.Read(array, 0, (int)info.Length);
            fs.Close();
            data = System.Text.Encoding.Default.GetString(array);
        }
        if (data.Length == 0)
            return ;
        JsonData jsonData = JsonMapper.ToObject(data);
        load(jsonData);
    }
    public void load(JsonData json)
    {
        clear();
        IDictionary<string, JsonData> jsond = json.ValueAsObject();
        /// Global
        if (jsond.ContainsKey("DelvelopmentMode"))
            m_DevelopmentMode = jsond["DelvelopmentMode"].ValueAsBoolean();
        if (jsond.ContainsKey("Money"))
            m_Money = json["Money"].ValueAsInt();
        if (jsond.ContainsKey("DriveLevel"))
            m_DriveLevel = (Driver.DriveLevel)jsond["DriveLevel"].ValueAsInt();
        if (jsond.ContainsKey("BattleLevel"))
            m_BattleLevel = jsond["BattleLevel"].ValueAsInt();
        if (jsond.ContainsKey("EasyOperation"))
            m_EasyOperation = jsond["EasyOperation"].ValueAsBoolean();
        if (jsond.ContainsKey("UIScale"))
            m_UIScale = (float)jsond["UIScale"].ValueAsDouble();
        if (jsond.ContainsKey("OpenAudio"))
            OpenAudio = jsond["OpenAudio"].ValueAsBoolean();


        int today = UtilsGame.GetSeedToday();
        // Lottery
        if (jsond.ContainsKey("Lottery"))
        {
            var jsonLottery = jsond["Lottery"].ValueAsObject();
            if(jsonLottery.ContainsKey("LastTermNumber"))
                m_LotteryLastTermNumber = jsonLottery["LastTermNumber"].ValueAsInt();
            if (jsonLottery.ContainsKey("CurTermNumber"))
                m_LotteryCurTermNumber = jsonLottery["CurTermNumber"].ValueAsInt();

            JsonData lastTermJson = null;
            if (today - 1 == m_LotteryCurTermNumber && jsonLottery.ContainsKey("CurTerm"))
            {
                m_LotteryLastTermNumber = today - 1;
                m_LotteryCurTermNumber = -1;
                lastTermJson = jsonLottery["CurTerm"];
            }
            else if (today - 1 == m_LotteryLastTermNumber && jsonLottery.ContainsKey("LastTerm"))
                lastTermJson = jsonLottery["LastTerm"];
            if(lastTermJson != null)
            {
                m_LotteryLastTerm.Clear();
                for (int i=0; i< lastTermJson.Count; ++i)
                {
                    int LotteryNumber = lastTermJson[i].ValueAsInt();
                    m_LotteryLastTerm.Add(LotteryNumber);
                }
            }
            if (today == m_LotteryCurTermNumber
                && jsonLottery.ContainsKey("CurTerm"))
            {
                m_LotteryCurTerm.Clear();
                for (int i = 0; i < jsonLottery["CurTerm"].Count; ++i)
                {
                    int LotteryNumber = jsonLottery["CurTerm"][i].ValueAsInt();
                    m_LotteryCurTerm.Add(LotteryNumber);
                }
            }
        }

        //  DriveLevelState
        if (jsond.ContainsKey("DriveLicenseState"))
        {
            var driveLicenseStateList = jsond["DriveLicenseState"].ValueAsObject();
            for (int i = 0; i < DriveLicenseState.Length; ++i)
            {
                if (driveLicenseStateList.ContainsKey("DriveLevel" + i))
                {
                    var driveLicenseState = driveLicenseStateList["DriveLevel" + i].ValueAsArray();
                    for(int j=0; j< EXAMINATION_NUMBER && j< driveLicenseState.Count; ++j)
                    {
                        DriveLicenseState[i, j] = driveLicenseState[j].ValueAsInt();
                    }
                }
            }
        }


        //  Ships
        if (jsond.ContainsKey("Ships"))
        {
            for (int j = 0; j < json["Ships"].Count; ++j)
            {
                var ship = Ship.loadByJson(json["Ships"][j]);
                if (ship)
                {
                    ship.gameObject.SetActive(false);
                    m_Ships.Add(ship);
                }
            }
        }
        if (jsond.ContainsKey("SelectShip"))
            SelectShip = json["SelectShip"].ValueAsInt();

        /// Items
        if (jsond.ContainsKey("Items"))
        {
            IDictionary<string, JsonData> items = json["Items"].ValueAsObject();
            foreach (var itemit in items)
            {
                string key = itemit.Key;
                int value = itemit.Value.ValueAsInt();
                Item item = ItemFactory.Instance.createItem(key);
                if (item != null)
                {
                    item.m_Number = value;
                    m_Items.Add(ItemFactory.Instance.GetItemType(key), item);
                }
                else
                {
                    Debug.LogWarning("not found item :" + key);
                }
            }
        }

        /// Shop
        if (jsond.ContainsKey("Shop"))
        {
            var jsonShop = jsond["Shop"].ValueAsObject();
            if (jsonShop.ContainsKey("UpdateDate"))
                m_ShopUpdateDate = jsonShop["UpdateDate"].ValueAsInt();
            if (jsonShop.ContainsKey("Weapon"))
            {
                Player.Instance.m_WeaponShopBuyIndices.Clear();
                var buyList = jsonShop["Weapon"].ValueAsArray();
                for (int i = 0; i < buyList.Count; ++i)
                {
                    Player.Instance.m_WeaponShopBuyIndices.Add(buyList[i].ValueAsInt());
                }
            }
            if (jsonShop.ContainsKey("Ship"))
            {
                Player.Instance.m_ShipShopBuyIndices.Clear();
                var buyList = jsonShop["Ship"].ValueAsArray();
                for (int i = 0; i < buyList.Count; ++i)
                {
                    Player.Instance.m_ShipShopBuyIndices.Add(buyList[i].ValueAsInt());
                }
            }
        }
    }

    public void clear()
    {
        m_Ships.Clear();
        m_Items.Clear();
    }


    public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        load();
    }
    public void OnUnSceneLoaded(Scene scene)
    {
        clear();
        SceneManager.sceneUnloaded -= OnUnSceneLoaded;
    }

}